<template>
  <div>
    <!-- <codemirror v-model="code" :options="cmOptions"></codemirror> -->
    <codemirror class="mycm" ref="cmref" :value="code" :options="cmOptions" @ready="onCmReady" @focus="onCmFocus" @input="onCmCodeChange" @cursorActivity="onCursorActivity" @inputRead="onInputRead">
    </codemirror>
  </div>
</template>

<script>
  import { codemirror } from 'vue-codemirror'
  import 'codemirror/lib/codemirror.css'
  // language
  // import 'codemirror/mode/javascript/javascript.js'
  import 'codemirror/mode/clike/clike.js'
  // import 'codemirror/mode/css/css.js'
  // theme 
  // import 'codemirror/theme/base16-dark.css'
  import 'codemirror/theme/idea.css'
  // 代码提示功能 具体语言可以从 codemirror/addon/hint/ 下引入多个
  import "codemirror/addon/hint/show-hint"
  // import "codemirror/addon/hint/javascript-hint"
  // import "codemirror/addon/hint/anyword-hint"
  import "codemirror/addon/hint/show-hint.css"
  // 高亮行功能
  // import "codemirror/addon/selection/active-line"
  // import "codemirror/addon/selection/selection-pointer"
  // 自动括号匹配功能
  // import 'codemirror/addon/edit/matchbrackets'

  // 代码段折叠功能
  import 'codemirror/addon/fold/foldcode'
  import 'codemirror/addon/fold/foldgutter'
  import 'codemirror/addon/fold/foldgutter.css'

  import 'codemirror/addon/fold/brace-fold'
  // import 'codemirror/addon/fold/comment-fold'
  // import 'codemirror/addon/fold/xml-fold.js';
  // import 'codemirror/addon/fold/indent-fold.js';
  // import 'codemirror/addon/fold/markdown-fold.js';
  // import 'codemirror/addon/fold/comment-fold.js';

  // merge功能
  // import 'codemirror/addon/merge/merge.css'
  // import 'codemirror/addon/merge/merge'
  // // google DiffMatchPatch
  // import DiffMatchPatch from 'diff-match-patch'
  // // DiffMatchPatch config with global
  // window.diff_match_patch = DiffMatchPatch;
  // window.DIFF_DELETE = -1;
  // window.DIFF_INSERT = 1;
  // window.DIFF_EQUAL = 0;


  // import "codemirror/addon/search/searchcursor.js";
  // import "codemirror/addon/search/search.js";

  import { js_beautify } from 'js-beautify'
  //   extraKeys: {
  // 	"Ctrl-Alt-L":(cm)=>{//自定义格式化代码的快捷键为“Ctrl-Alt-L”
  // 		this.editorValue = js_beautify(cm.getValue())
  // 		this.$emit('onChangeCode',js_beautify(cm.getValue()))
  // 	}
  // },
  export default {
    components: {
      codemirror
    },
    props: {},
    data() {
      return {
        // code: 'function(){let a=1}',
        code: `import com.demo.util.MyInterface;  private class InnerClass {public int zero() {return 0; }}`,
        cmOptions: {
          // 'true'为只读, 如果为'nocursor' 不仅仅为只读 连光标都无法在区域聚焦
          readOnly: false,
          tabSize: 2,
          // mode: 'javascript',
          mode: 'text/x-java', // clike: text/x-java"  
          theme: 'idea',
          lineNumbers: true,
          line: true,
          lineWrapping: true, // 自动换行
          styleActiveLine: true, // 高亮选中行
          hintOptions: {
            completeSingle: false, // 当匹配只有一项的时候是否自动补全
            hint: this.handleShowHint,
          },
          // matchBrackets: true,
          // smartIndent: true, // 自动缩进
          autoCloseBrackets: true, // 在键入时将自动关闭括号和引号
          foldGutter: true,
          gutters: [
            "CodeMirror-lint-markers",
            "CodeMirror-linenumbers",
            "CodeMirror-foldgutter"
          ],
          highlightSelectionMatches: {
            minChars: 2,
            style: "matchhighlight",
            showToken: true
          },
          // autocorrect: true,  // 自动更正
          // spellcheck: true,  // 拼写检查
          // keyMap: ({
          //   'Ctrl-S': () => {
          //     console.log('保存')
          //   }
          // })
        }
      }
    },
    computed: {
      codemirror() {
        return this.$refs.cmref.codemirror
      }
    },
    watch: {},
    mounted() {
      console.log('this is current codemirror object', codemirror, this.codemirror)
    },
    methods: {
      onInputRead(cm) {
        // cm.showHint();
      },
      find() {
        this.$refs.cm.comdemirror.execCommand("find")
      },
      onCmReady(cm) {
        // console.log('the editor is readied!', cm)
        cm.addKeyMap({
          'Ctrl-S': () => {
            console.log('保存')
            this.code = js_beautify(cm.getValue(), { indent_size: 2, space_in_empty_paren: true })
          },
          'Ctrl-F': () => {
            console.log('搜索')
            cm.execCommand("find")
          },
          'Ctrl-Alt-L': () => {
            console.log('格式化')
            this.code = js_beautify(cm.getValue(), { indent_size: 2, space_in_empty_paren: true })
          }
        })
      },
      onCmFocus(cm) {
        // console.log('the editor is focus!', cm)
      },
      onCmCodeChange(newCode) {
        this.codemirror.showHint(this.handleShowHint())
        // this.code = newCode
      },
      trimLeft(str) {
        for (var i = 0; i < str.length; i++) {
          if (str.charAt(i) != " ") break;
        }
        //console.log(i); 打印第一个非空格字符的index
        return str.slice(i, str.length)
      },
      // 代码提示处理
      handleShowHint() {
        const hintList = [
          { name: "xiaohong", value: "xiaohong" },
          { name: "xiaozhang------ffff", value: [{ name: "xiaoli" }, { name: "xiaosun" }] }
        ]
        const cmInstance = this.$refs.cmref.codemirror
        // 得到光标
        let cursor = cmInstance.getCursor()
        // 得到行内容
        let cursorLine = cmInstance.getLine(cursor.line)
        // 得到光标位置
        let end = cursor.ch
        let start = end
        const Two = `${cursorLine.charAt(start - 2)}${cursorLine.charAt(start - 1)}`
        const One = `${cursorLine.charAt(start - 1)}`
        let list = []
        // console.log('cursorLine=', cursorLine)

        if (cursorLine.trim() != '') {
          for (let i = 0; i < hintList.length; i++) {
            const element = hintList[i]
            if (element.name.startsWith(cursorLine.trimLeft())) {
              list.push(element.name)
            }
          }
        }
        // if (Two === "${") {
        //   hintList.forEach(e => {
        //     list.push(e.name)
        //   })
        // } else if (One === ".") {
        //   let lastIndex = cursorLine.lastIndexOf('${', start)
        //   let key = cursorLine.substring(lastIndex + 2, start - 1)
        //   list = []
        //   hintList.forEach((e) => {
        //     if (e.name === key && lastIndex !== -1 && Object.prototype.toString.call(e.value) === '[object Array]') {
        //       e.value.forEach(el => {
        //         list.push(el.name)
        //       })
        //     }
        //   })
        // }
        // 得到光标标识
        let token = cmInstance.getTokenAt(cursor)
        // console.log(cmInstance, cursor, cursorLine, end, token)
        console.log('提示list', list)
        return {
          list: list,
          // list: [
          // {
          //   text: "hello",
          //   displayText: "你好呀",
          //   displayInfo: "提示信息1",
          //   render: this.hintRender
          // },
          // {
          //   text: "world",
          //   displayText: "世界",
          //   displayInfo: "提示信息2",
          //   render: this.hintRender
          // }],
          from: { ch: end, line: cursor.line },
          to: { ch: token.end, line: cursor.line },
        }
      },
      //代码提示处理
      handleShowHint2() {
        const cmInstance = this.codemirror
        let cursor = cmInstance.getCursor() // 得到光标
        let curLine = cmInstance.getLine(cursor.line) // 得到行内容
        console.log('cmInstance.hint', cmInstance.hint)
        const jshint = cmInstance.hint.javascript(cmInstance, this.cmOptions) //获取js自带的提示（cmOptions是codemirror的option配置）
        const anyhint = cmInstance.hint.anyword(cmInstance, this.cmOptions) //获取anyword自带提示
        const definehint = [
          "callback()",
          "unique()",
          "many()",
          "log"
        ] // 自定义提示
        var word = /[\w$]+/
        var end = cursor.ch,
          start = end
        while (start && word.test(curLine.charAt(start - 1))) --start
        var curWord = start != end && curLine.slice(start, end) //此处为了解决防止curLine中有\t、空格而导致匹配不成功的情况
        let found = []

        function maybeAdd(str) {
          if (str.lastIndexOf(curWord, 0) == 0 && !arrayContains(found, str))
            found.push(str)
        }
        forEach(definehint, maybeAdd)

        function arrayContains(arr, item) {
          if (!Array.prototype.indexOf) {
            var i = arr.length
            while (i--) {
              if (arr[i] === item) {
                return true
              }
            }
            return false
          }
          return arr.indexOf(item) != -1
        }

        function forEach(arr, f) {
          for (var i = 0, e = arr.length; i < e; ++i) f(arr[i])
        }
        const words = new Set([...found, ...anyhint.list, ...jshint.list]) //合并所有提示
        if (words.size > 0) {
          return {
            list: Array.from(words),
            from: jshint.from,
            to: jshint.to
          }
        }

      },
      hintRender(element, self, data) {
        let div = document.createElement("div");
        div.setAttribute("class", "autocomplete-div");

        let divText = document.createElement("div");
        divText.setAttribute("class", "autocomplete-name");
        divText.innerText = data.displayText;

        let divInfo = document.createElement("div");
        divInfo.setAttribute("class", "autocomplete-hint");
        divInfo.innerText = data.displayInfo;

        div.appendChild(divText);
        div.appendChild(divInfo);
        element.appendChild(div);
      },
      onCursorActivity(cm) {
        console.log('--onCursorActivity--', cm)
        // cm.showHint(this.handleShowHint())
        // cm.refresh()
      },
    },
  }
</script>

<style scoped>
  ::v-deep .CodeMirror {
    height: calc(100vh - 96px);
  }

  /* ::v-deep .CodeMirror-hints {
    z-index: 3000 !important;
  }

  ::v-deep .CodeMirror-lint-tooltip {
    z-index: 3000 !important;
  } */

  .autocomplete-div {
    display: inline-block;
    width: 100%;
  }

  .autocomplete-name {
    display: inline-block;
  }

  .autocomplete-hint {
    display: inline-block;
    float: right;
    color: #0088ff;
    margin-left: 1em;
  }
</style>